﻿Imports System
Imports System.IO
Imports System.Reflection
Imports System.Runtime.InteropServices
Imports System.Runtime.Serialization
Imports System.Runtime.Serialization.Formatters.Binary
Imports System.Workflow.ComponentModel

Namespace System.Workflow.Activities
    Friend Class InvokeHelper
        ' Methods
        Friend Shared Function CloneOutboundValue(ByVal source As Object, ByVal formatter As BinaryFormatter, ByVal name As String) As Object
            If ((source Is Nothing) OrElse source.GetType.IsValueType) Then
                Return source
            End If
            Dim cloneable As ICloneable = [TryCast](source,ICloneable)
            If (Not cloneable Is Nothing) Then
                Return cloneable.Clone
            End If
            Dim serializationStream As New MemoryStream(&H400)
            Try 
                formatter.Serialize(serializationStream, source)
            Catch exception As SerializationException
                Throw New InvalidOperationException(SR.GetString("Error_CallExternalMethodArgsSerializationException", New Object() { name }), exception)
            End Try
            serializationStream.Position = 0
            Return formatter.Deserialize(serializationStream)
        End Function

        Friend Shared Function GetParameters(ByVal methodBase As MethodBase, ByVal parameterBindings As WorkflowParameterBindingCollection) As Object()
            Dim parameters As ParameterInfo() = methodBase.GetParameters
            Dim objArray As Object() = New Object(parameters.Length  - 1) {}
            Dim index As Integer = 0
            Dim info As ParameterInfo
            For Each info In parameters
                If parameterBindings.Contains(info.Name) Then
                    Dim binding As WorkflowParameterBinding = parameterBindings.Item(info.Name)
                    objArray(index) = binding.Value
                End If
                index += 1
            Next
            Return objArray
        End Function

        Friend Shared Function GetParameters(ByVal methodBase As MethodBase, ByVal parameterBindings As WorkflowParameterBindingCollection, <Out> ByRef parameterModifiers As ParameterModifier()) As Object()
            Dim parameters As ParameterInfo() = methodBase.GetParameters
            Dim objArray As Object() = New Object(parameters.Length  - 1) {}
            If (objArray.Length = 0) Then
                parameterModifiers = New ParameterModifier(0  - 1) {}
                Return objArray
            End If
            Dim index As Integer = 0
            Dim formatter As BinaryFormatter = Nothing
            Dim modifier As New ParameterModifier(objArray.Length)
            Dim info As ParameterInfo
            For Each info In parameters
                If info.ParameterType.IsByRef Then
                    modifier.Item(index) = True
                Else
                    modifier.Item(index) = False
                End If
                If parameterBindings.Contains(info.Name) Then
                    Dim binding As WorkflowParameterBinding = parameterBindings.Item(info.Name)
                    If (formatter Is Nothing) Then
                        formatter = New BinaryFormatter
                    End If
                    objArray(index) = InvokeHelper.CloneOutboundValue(binding.Value, formatter, info.Name)
                End If
                index += 1
            Next
            Dim modifierArray As ParameterModifier() = New ParameterModifier() { modifier }
            parameterModifiers = modifierArray
            Return objArray
        End Function

        Friend Shared Sub InitializeParameters(ByVal methodBase As MethodInfo, ByVal parameterBindings As WorkflowParameterBindingCollection)
            Dim info As ParameterInfo
            For Each info In methodBase.GetParameters
                If Not parameterBindings.Contains(info.Name) Then
                    parameterBindings.Add(New WorkflowParameterBinding(info.Name))
                End If
            Next
            If ((Not methodBase.ReturnType Is GetType(Void)) AndAlso Not parameterBindings.Contains("(ReturnValue)")) Then
                parameterBindings.Add(New WorkflowParameterBinding("(ReturnValue)"))
            End If
        End Sub

        Friend Shared Sub SaveOutRefParameters(ByVal actualParameters As Object(), ByVal methodBase As MethodBase, ByVal parameterBindings As WorkflowParameterBindingCollection)
            Dim index As Integer = 0
            Dim formatter As BinaryFormatter = Nothing
            Dim info As ParameterInfo
            For Each info In methodBase.GetParameters
                If (parameterBindings.Contains(info.Name) AndAlso (info.ParameterType.IsByRef OrElse (info.IsIn AndAlso info.IsOut))) Then
                    Dim binding As WorkflowParameterBinding = parameterBindings.Item(info.Name)
                    If (formatter Is Nothing) Then
                        formatter = New BinaryFormatter
                    End If
                    binding.Value = InvokeHelper.CloneOutboundValue(actualParameters(index), formatter, info.Name)
                End If
                index += 1
            Next
        End Sub

    End Class
End Namespace

